﻿using System;
using System.IO;
using static Vanara.PInvoke.Kernel32;

namespace Vanara.PInvoke.Tests
{
	/// <summary>Creates a unique temporary file in the %APPDATA%\Temp folder and deletes it when disposed.</summary>
	/// <seealso cref="System.IDisposable"/>
	public class TempFile : IDisposable
	{
		/// <summary>The default value inserted into the file if not overridden by constructor parameter.</summary>
		public const string tmpstr = @"Temporary";

		/// <summary>Initializes a new instance of the <see cref="TempFile"/> class and retrieves a handle to the file.</summary>
		/// <param name="dwDesiredAccess">The desired access.</param>
		/// <param name="dwShareMode">The share mode.</param>
		/// <param name="dwCreationDisposition">The creation disposition.</param>
		/// <param name="dwFlagsAndAttributes">The flags and attributes.</param>
		public TempFile(Kernel32.FileAccess dwDesiredAccess, FileShare dwShareMode, FileMode dwCreationDisposition = FileMode.OpenOrCreate,
			FileFlagsAndAttributes dwFlagsAndAttributes = FileFlagsAndAttributes.FILE_ATTRIBUTE_NORMAL) : this(string.Empty) =>
			hFile = CreateFile(FullName, dwDesiredAccess, dwShareMode, null, dwCreationDisposition, dwFlagsAndAttributes, IntPtr.Zero);

		/// <summary>Initializes a new instance of the <see cref="TempFile"/> class with the specified contents.</summary>
		/// <param name="contents">
		/// The text inserted into the file. If this value is <see langword="null"/>, the file is not created on disk.
		/// </param>
		public TempFile(string contents = tmpstr)
		{
			FullName = Path.GetTempFileName();
			if (contents is null)
				File.Delete(FullName);
			else if (contents != string.Empty)
				File.WriteAllText(FullName, contents);
		}

		/// <summary>Initializes a new instance of the <see cref="TempFile"/> class with the specified extension and contents.</summary>
		/// <param name="ext">The file extension.</param>
		/// <param name="contents">
		/// The text inserted into the file. If this value is <see langword="null"/>, the file is not created on disk.
		/// </param>
		public TempFile(string ext, string contents = tmpstr)
		{
			FullName = Path.Combine(Path.GetTempPath(), $"tmp{Guid.NewGuid():N}.{ext.TrimStart('.')}");
			if (contents is not null)
				File.WriteAllText(FullName, contents);
		}

		/// <summary>Gets the full path of the temporary file.</summary>
		/// <value>The full path of the temporary file.</value>
		public string FullName { get; }

		/// <summary>
		/// Gets the file handle if created with the <see cref="TempFile.TempFile(Kernel32.FileAccess, FileShare, FileMode,
		/// FileFlagsAndAttributes)"/> constructor.
		/// </summary>
		/// <value>The file handle.</value>
		public SafeHFILE hFile { get; }

		/// <summary>Releases unmanaged and - optionally - managed resources.</summary>
		/// <returns></returns>
		void IDisposable.Dispose()
		{
			hFile?.Dispose();
			if (File.Exists(FullName))
				File.Delete(FullName);
		}
	}
}